package com.jtcl.log.service.impl;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.FileAppender;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import com.jtcl.log.config.bean.SessionDataBean;
import com.jtcl.log.service.IReadLogService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpSession;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

@Slf4j
public class LogBackReadLogService implements IReadLogService {
	
	@Override
	public List<String> getLogPath() {
		List<String> logFilePaths = new ArrayList<String>();
		LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
		for (ch.qos.logback.classic.Logger logger : context.getLoggerList()) {
			for (Iterator<Appender<ILoggingEvent>> index = logger.iteratorForAppenders(); index.hasNext();) {
				Appender<ILoggingEvent> appender = index.next();
				if (appender instanceof FileAppender) {
					FileAppender<ILoggingEvent> fileAppender = (FileAppender<ILoggingEvent>) appender;
					File file = new File(fileAppender.getFile());
					String canonicalPath;
					try {
						canonicalPath = file.getCanonicalPath();
						logFilePaths.add(canonicalPath);
					} catch (IOException e) {
						log.error("日志文件获取失败");
						// e.printStackTrace();
					}
					
				}
			}
		}
		return logFilePaths;
	}
	
	 @Override
	public String getLogContent(HttpSession session, String filePath) {
		String result = "";
		try {
			// 获取session存储对象
			String sessionAttrName = DigestUtils.md5DigestAsHex(filePath.getBytes());
			SessionDataBean sessionData = (SessionDataBean) session.getAttribute(sessionAttrName);
			
			// session存储对象不存在则初始化
			if (Objects.isNull(sessionData)) {
				int fileLineLength = getFileLineLength(filePath);
				sessionData = new SessionDataBean(fileLineLength-200,fileLineLength);
			}else {
				sessionData.lineChange(-1);
			}
			
			List<String> fileLines = getFileLine(filePath, sessionData);
			
			for(int i = 0; i < fileLines.size(); i++) {
				fileLines.set(i, dealLine(sessionData, fileLines.get(i)));
			}
			// 日志换行 
			result = CollUtil.join(fileLines, "<br/>");
			
			session.setAttribute(sessionAttrName, sessionData);
		} catch (FileNotFoundException e) {
			log.error("日志内容读取失败");
			// e.printStackTrace();
		}
		return result;
	}
	
	/** 
	 * <p>Title:获取文件行数</p>
	 * <p>Description:</p>
	 * @author mqh
	 * @date 2020年3月30日  
	 * @version 1.0 
	 * @param filePath
	 * @return
	 * @throws FileNotFoundException 
	 */
	private int getFileLineLength(String filePath) throws FileNotFoundException {
		int lines = 0;
//		TimeInterval timer = DateUtil.timer();
		try {
			BufferedReader reader = new BufferedReader(new FileReader(filePath));
			String s = reader.readLine();
			while (s != null) // 确定行数
			{
				lines++;
				s = reader.readLine();
			}
			reader.close();
//			log.error("buffer:行数：{},时间：{}ms",lines,timer.intervalRestart());
		} catch (IOException e) {
			log.error("获取文件行数失败");
//			e.printStackTrace();
		} 
		
		return lines;
	}
	
	/** 
	 * <p>Title:获取文件的行区间信息</p>
	 * <p>Description:</p>
	 * @author mqh
	 * @date 2020年3月30日  
	 * @version 1.0 
	 * @param filePath
	 * @return
	 */
	private List<String> getFileLine(String filePath,SessionDataBean sessionData) {
//		TimeInterval timer = DateUtil.timer();
		List<String> lines = new ArrayList<String>();
		int count = 0;
		try {
			BufferedReader reader = new BufferedReader(new FileReader(filePath));
			String s = reader.readLine();
			while (s != null) // 确定行数
			{
				if(count >= sessionData.getStartLine() && (count < sessionData.getEndLine() || sessionData.getEndLine() == -1)) {
					lines.add(s.toString());
				}
				count++;
				s = reader.readLine();
			}
			sessionData.setEndLine(count);
			reader.close();
//			log.error("读取内容时间：{}ms",timer.interval());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} // 定义行数
		
		return lines;
	}
	
	/**
	 * <p>Title:行处理，加颜色区分等</p>
	 * <p>Description:</p>
	 * @author mqh
	 * @date 2020年3月30日  
	 * @version 1.0 
	 * @param sessionData 会话存储的对象
	 * @param line 单行日志
	 * @return
	 */
	private String dealLine(SessionDataBean sessionData,String line) {
		// 先转义
		line = line.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"",
							"&quot;");
		// 处理占位空格
		line = line.replaceAll(" ", "&ensp;");
		// line = line.replaceAll("\\.", ".&nbsp;");
		
		// 处理等级
		line = line.replace("DEBUG", "<span style='color: blue;'>DEBUG</span>");
		line = line.replace("INFO", "<span style='color: green;'>INFO</span>");
		line = line.replace("WARN", "<span style='color: orange;'>WARN</span>");
		line = line.replace("ERROR", "<span style='color: red;'>ERROR</span>");
		
		// 不是日志标准开头，缩进处理
		if (line.indexOf("[") != 0) {
			// log.info(line.indexOf("at") + "");
			if (line.indexOf("at") == 1) {// 如果是at开头，则缩进4字符，线程堆栈信息
				line = "&nbsp;&nbsp;&nbsp;" + line;
			} else {// 否则缩进2字符，线程堆栈信息
				line = "&nbsp;&nbsp;" + line;
			}
		}
		
		// 将日志内容染色
		int lastIndexOf = line.lastIndexOf("&ensp;-&ensp;");
		if (lastIndexOf != -1) {
			String newMsg = line.substring(lastIndexOf, line.length());
			line = line.substring(0, lastIndexOf) + "<span style='color: #000;'>" + newMsg + "</span>";
		} else {
			line = "<span style='color: #000;'>" + line + "</span>";
		}
		
		// requestId染色
		String regStr = ReUtil.get("\\[requestId-.*?\\]", line, 0);
		if(Objects.nonNull(regStr)) {
			if (!regStr.equals(sessionData.getRequestId())) {
				sessionData.setRequestId(regStr);
				sessionData.colorIndexChange();
			}
			line = line.replace(regStr, "<span style='color: " + sessionData.getColor() + ";'>" + regStr + "</span>");
		}
		
		// requstId = regStr == null ;
		// requstId = line.matches("\\[requestId-.+\\]");
		
		line = "<code style='color: #AAA;'>" + line + "</code>";
		
		// 处理类名
		/*
		 * String[] split = line.split("]"); if (split.length >= 2) { String[] split1 =
		 * split[1].split("-"); if (split1.length >= 2) { line = split[0] + "]" +
		 * "<span style='color: #298a8a;'>" + split1[0] + "</span>" + "-" + split1[1]; }
		 * }
		 */
		return line;
	}
}
